using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using Newtonsoft.Json;
using NotifyCenter.Sender.Options;
using NotifyCenter.Sender.ResponseModels;
namespace NotifyCenter.Sender;

/// <summary>
/// Sends Feishu interactive template cards via custom bot webhook.
/// </summary>
public class FeishuGroupCardSender : ISender
{
    private readonly HttpClient _httpClient;

    public string Type => "FeishuGroupCard";

    public FeishuGroupCardSender()
    {
        _httpClient = new HttpClient
        {
            Timeout = TimeSpan.FromSeconds(30)
        };
    }

    public async Task SendAsync(string configurationJson, string receiver, string content, CancellationToken cancellationToken = default)
    {
        var config = DeserializeConfiguration(configurationJson);
        var receiverOptions = DeserializeReceiver(receiver);
        var templateVariables = DeserializeTemplateVariables(content);

        var cardPayload = new
        {
            type = "template",
            data = new
            {
                template_id = config.CardConfiguration.CardId,
                template_version_name = config.CardConfiguration.CardVersion,
                template_variable = templateVariables != null && templateVariables.Count > 0 ? templateVariables : null
            }
        };

        var request = BuildOfficialRequest(receiverOptions.SignSecret, "interactive", null);
        request.Card = cardPayload;

        var jsonSettings = new JsonSerializerSettings
        {
            NullValueHandling = NullValueHandling.Ignore,
            StringEscapeHandling = StringEscapeHandling.EscapeNonAscii
        };
        var requestJson = JsonConvert.SerializeObject(request, jsonSettings);
        var httpContent = new StringContent(requestJson, Encoding.UTF8, "application/json");

        using var response = await _httpClient.PostAsync(receiverOptions.WebHookUrl, httpContent, cancellationToken);
        response.EnsureSuccessStatusCode();

        var responseContent = await response.Content.ReadAsStringAsync(cancellationToken);
        var botResponse = JsonConvert.DeserializeObject<FeishuBotResponse>(responseContent)
                          ?? throw new InvalidOperationException("Unexpected Feishu bot response.");

        if (!botResponse.IsSuccess)
        {
            var errorTips = GetOfficialErrorTips(botResponse.Code);
            throw new InvalidOperationException($"Failed to send template card: Code={botResponse.Code}, Msg={botResponse.Msg}. {errorTips}");
        }
    }

    private static FeishuGroupCardSenderConfiguration DeserializeConfiguration(string configurationJson)
    {
        if (string.IsNullOrWhiteSpace(configurationJson))
        {
            throw new ArgumentNullException(nameof(configurationJson), "configurationJson cannot be null or empty.");
        }

        var config = JsonConvert.DeserializeObject<FeishuGroupCardSenderConfiguration>(configurationJson)
                     ?? throw new InvalidOperationException("Invalid configurationJson: failed to deserialize FeishuGroupCardSenderConfiguration.");

        if (string.IsNullOrWhiteSpace(config.CardConfiguration.CardId))
        {
            throw new InvalidOperationException("configurationJson is missing card:card_id.");
        }

        if (string.IsNullOrWhiteSpace(config.CardConfiguration.CardVersion))
        {
            throw new InvalidOperationException("configurationJson is missing card:card_version.");
        }

        return config;
    }

    private static BotGroupWebHookReceiver DeserializeReceiver(string receiver)
    {
        if (string.IsNullOrWhiteSpace(receiver))
        {
            throw new ArgumentNullException(nameof(receiver), "receiver cannot be null or empty.");
        }

        var receiverObject = JsonConvert.DeserializeObject<BotGroupWebHookReceiver>(receiver);
        if (string.IsNullOrWhiteSpace(receiverObject?.WebHookUrl))
        {
            throw new InvalidOperationException("receiver must contain webhook_url.");
        }

        return receiverObject;
    }

    private static Dictionary<string, object> DeserializeTemplateVariables(string content)
    {
        if (string.IsNullOrWhiteSpace(content))
        {
            return new Dictionary<string, object>();
        }

        try
        {
            return JsonConvert.DeserializeObject<Dictionary<string, object>>(content)
                   ?? new Dictionary<string, object>();
        }
        catch (JsonException ex)
        {
            throw new InvalidOperationException("content must be a valid JSON object for template variables.", ex);
        }
    }

    private static string ComputeOfficialSign(string stringToSign)
    {
        var keyBytes = Encoding.UTF8.GetBytes(stringToSign);
        using var hmac = new HMACSHA256(keyBytes);
        var hashBytes = hmac.ComputeHash(Array.Empty<byte>());
        return Convert.ToBase64String(hashBytes);
    }

    private FeishuBotRequest BuildOfficialRequest(string signSecret, string msgType, object? content)
    {
        var request = new FeishuBotRequest
        {
            MsgType = msgType,
            Content = content
        };

        if (!string.IsNullOrWhiteSpace(signSecret))
        {
            var timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
            var stringToSign = $"{timestamp}\n{signSecret}";
            var sign = ComputeOfficialSign(stringToSign);

            request.Timestamp = timestamp;
            request.Sign = sign;
        }

        return request;
    }

    private static string GetOfficialErrorTips(int code)
    {
        return code switch
        {
            19021 => "Check timestamp/signature when Enable Signature is on.",
            19022 => "Server IP not in robot whitelist.",
            400014 => "Robot removed from chat or chat_id invalid.",
            _ => "Refer to Feishu bot docs for error codes: https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot"
        };
    }
}
